package io.netty.example.test.client;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class RequestFuture {
    private static final AtomicInteger aid = new AtomicInteger();
    private int id;
    private static Map<Integer, RequestFuture> futures = new ConcurrentHashMap<Integer, RequestFuture>();
    private Object request;
    private Object result;
    private long timeout = 5000L;
    public Lock lock = new ReentrantLock();
    public Condition condition = lock.newCondition();

    public RequestFuture() {
        id = aid.incrementAndGet();
        addFuture(this);
    }

    public static void addFuture(RequestFuture future) {
        futures.put(future.getId(), future);
    }

    public Object get(){
//        synchronized (this) {
//            while (result == null) {
//                try {
//                    this.wait(timeout);
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }
//            }
//        }
        try {
            lock.lock();
            while (result == null) {
                condition.await(timeout, TimeUnit.MILLISECONDS);
            }
        } catch (Exception e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }


        return result;
    }

    public static void receive(Response response){
        RequestFuture future = futures.remove(response.getId());
        if (future!=null) {
            future.setResult(response.getResult());
        }
//        synchronized (future) {
//            future.notify();
//        }
        try {
            future.lock.lock();
            future.condition.signal();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            future.lock.unlock();
        }
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public Object getRequest() {
        return request;
    }

    public void setRequest(Object request) {
        this.request = request;
    }

    public Object getResult() {
        return result;
    }

    public void setResult(Object result) {
        this.result = result;
    }

    public long getTimeout() {
        return timeout;
    }

    public void setTimeout(long timeout) {
        this.timeout = timeout;
    }
}
